package com.northpool.operator.http.version;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import com.northpool.operator.annotation.InputParam;
import com.northpool.operator.annotation.InputParams;
import com.northpool.operator.annotation.OperatorInfo;
import com.northpool.operator.common.algorithm.OperatorTestBuild;
import com.northpool.operator.common.algorithm.TestParamBuilder;
import com.northpool.operator.common.minio.MinIOUtil;
import com.northpool.operator.common.util.XmlParser;
import com.northpool.operator.http.bean.AppMetadata;
import com.northpool.operator.http.bean.ExpParamBean;
import com.northpool.operator.http.bean.HttpOperatorBean;
import com.northpool.operator.http.bean.ResultApiBean;
import com.northpool.operator.http.bean.StartApiBean;
import com.northpool.operator.param.ParamTool;
import com.northpool.operator.type.TypeEnum;
import com.northpool.operator.utils.StpOperatorHelper;
import io.minio.Result;
import io.minio.messages.Item;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

@OperatorInfo(ref = "V2ToV3Operator", name = "HTTP算子XML升级", version = "0.0.2_0.0.3")
public class V2ToV3Operator extends StpOperatorHelper {

    @InputParams({
            @InputParam(ref = "path", name = "minio中算子路径", desc = "minio中对象路径, 如: apps/supermap/"),
            @InputParam(ref = "minioEndpoint", name = "对象存储地址", desc = "http://ip:port"),
            @InputParam(ref = "bucket", name = "桶名称", desc = "桶名称, 如: stp-minio"),
            @InputParam(ref = "accessKey", name = "minio令牌", desc = "minio令牌, 如: northpool", type = TypeEnum.STRING),
            @InputParam(ref = "secretKey", name = "minio密钥", desc = "minio密钥, 如: xxxxxxx", type = TypeEnum.STRING),
    })
    public V2ToV3Operator() {
    }

    public static void main(String[] args) throws Exception {
        OperatorTestBuild.execute(V2ToV3Operator.class, TestParamBuilder.aBuilder()
                .param("path", "apps/supermap/")
                .param("minioEndpoint", "http://northpool.work:9000")
//                .param("minioEndpoint", "http://192.168.185.9:9000")
//                .param("minioEndpoint", "http://192.168.164.45:9000")
                .param("bucket", "stp-minio")
                .param("accessKey", "northpool")
                .param("secretKey", "piesat@123")
                .build());
        System.exit(0);
    }

    private static String bucket;
    private static String s3Endpoint;

    @Override
    public void execute(ParamTool params) throws Exception {
        bucket = params.getStr("bucket");
        String path = params.getStr("path");
        s3Endpoint = params.getStr("minioEndpoint");
        String accessKey = params.getStr("accessKey");
        String secretKey = params.getStr("secretKey");

        MinIOUtil minioUtil = new MinIOUtil(s3Endpoint, accessKey, secretKey);
        try {
            processDirItem(minioUtil, bucket, path);
        } catch (Exception ex) {
            this.error("处理失败" + ex.getMessage());
            failedExit();
        }
    }

    private void processDirItem(MinIOUtil minioUtil, String bucket, String path) throws Exception {
        Iterable<Result<Item>> results = minioUtil.listObjects(bucket, path);
        List<String> dirList = new LinkedList<>();
        Boolean existsMeta = false;
        // 遍历所有文件列表
        for (Result<Item> result : results) {
            Item item = result.get();
            boolean dir = item.isDir();
            if (dir) {
                dirList.add(item.objectName());
            } else if(item.objectName().endsWith("/STP_META.xml")){
                existsMeta = true;
            }
        }

        if (existsMeta) {
            try {
                processFileItem(minioUtil, bucket, path);
            } catch (Exception ex) {
                error("异常文件：" + path + ",异常信息" + ex.getMessage());
            }
        }

        for (String dirObjName : dirList) {
            processDirItem(minioUtil, bucket, dirObjName);
        }
    }

    private void processFileItem(MinIOUtil minioUtil, String bucket, String parentPath) throws Exception {
        String metaPath = parentPath + "STP_META.xml";
        InputStream metaInputStream = minioUtil.getObject(bucket, metaPath);
        AppMetadata appMetadata = XmlParser.parserByInputStream(metaInputStream, AppMetadata.class);
        if (appMetadata == null) { // 为空就直接跳过
            error("节点元数据信息描述为空： " + metaPath);
            return  ;
        }

        String packageFile = appMetadata.getPackageFile();
        if (!packageFile.endsWith(".xml")) {
            return;
        }
        InputStream xmlInputStream = minioUtil.getObject(bucket, parentPath + packageFile);
        HttpOperatorBean operatorBean = XmlParser.parserByInputStream(xmlInputStream, HttpOperatorBean.class);

        // 去除废弃的属性
        operatorBean.setDisk(null);
        operatorBean.setMemory(null);

        if (StrUtil.isBlank(operatorBean.getRef())) {
            operatorBean.setRef(operatorBean.getName());
            operatorBean.setName(StrUtil.isNotBlank(operatorBean.getTitle()) ? operatorBean.getTitle() : operatorBean.getDescription());
            operatorBean.setTitle(null);
        } else if (StrUtil.isNotBlank(operatorBean.getRef()) && Objects.nonNull(operatorBean.getTitle())) {
            operatorBean.setTitle(null);
        }
        StartApiBean startApi = operatorBean.getStartApi();
        for (ExpParamBean expParamBean : startApi.getStartParam()) {
            if (StrUtil.isBlank(expParamBean.getRef())) {
                expParamBean.setRef(expParamBean.getName());
                expParamBean.setName(StrUtil.isNotBlank(expParamBean.getTitle()) ? expParamBean.getTitle() : expParamBean.getDescription());
                expParamBean.setTitle(null);
            }
            // 参数是否必填
            if (expParamBean.getInout().equalsIgnoreCase("OUT") && Objects.isNull(expParamBean.getRequired())) {
                expParamBean.setRequired(true);
            } else if (Objects.isNull(expParamBean.getRequired())){
                expParamBean.setRequired(false);
            }

            // 非填参数的默认值
            if (!expParamBean.getRequired() && Objects.isNull(expParamBean.getValue())) {
                expParamBean.setValue("");
            }
            // in参数没有exp
            if (expParamBean.getInout().equalsIgnoreCase("IN") && !Objects.isNull(expParamBean.getExp())) {
                expParamBean.setExp(null);
            }
            expParamBean.setType(getDslTypeStr(expParamBean.getType()));
        }

        ResultApiBean resultApi = operatorBean.getResultApi();
        List<ExpParamBean> resultParam = resultApi == null ? ListUtil.empty() : resultApi.getResultParam();
        for (ExpParamBean expParamBean : resultParam) {
            if (StrUtil.isBlank(expParamBean.getRef())) {
                expParamBean.setRef(expParamBean.getName());
                expParamBean.setName(StrUtil.isNotBlank(expParamBean.getTitle()) ? expParamBean.getTitle() : expParamBean.getDescription());
                expParamBean.setTitle(null);
            }
            if (Objects.isNull(expParamBean.getRequired())) {
                expParamBean.setRequired(true);
            }
            expParamBean.setType(getDslTypeStr(expParamBean.getType()));
        }

        String targetXml = XmlParser.convertToXml(operatorBean);
//        log(targetXml);
        minioUtil.removeObject(bucket, parentPath + packageFile);
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(targetXml.getBytes(StandardCharsets.UTF_8));
        minioUtil.putObject(bucket, parentPath + packageFile, byteArrayInputStream, "text/plain; charset=utf-8");
        log("处理完成: {}", parentPath + packageFile);
    }

    private static String getDslTypeStr(String type) {
        if ("STRING".equalsIgnoreCase(type)) {
            return "STRING";
        } else if ("BOOLEAN".equalsIgnoreCase(type) || "BOOL".equalsIgnoreCase(type)) {
            return "BOOL";
        } else if ("INTEGER".equalsIgnoreCase(type) || "LONG".equalsIgnoreCase(type) || "NUMBER".equalsIgnoreCase(type)) {
            return "NUMBER";
        } else if ("DB".equalsIgnoreCase(type)) {
            return "DB";
        } else if ("DATABASE".equalsIgnoreCase(type)) {
            return "DATABASE";
        } else if ("DATASOURCE".equalsIgnoreCase(type)) {
            return "DATASOURCE";
        } else if ("ENUM".equalsIgnoreCase(type)) {
            return "ENUM";
        } else {
            throw new RuntimeException("暂不支持的类型：" + type);
        }
    }
}
